Beyond the x and y aesthetics
Switch focus to exploring aesthetic mappings, instead of geoms.
library(gapminder)
library(tidyverse)
[30m── [1mAttaching packages[22m ─────────── tidyverse 1.2.1 ──[39m
[30m[32m✔[30m [34mggplot2[30m 3.0.0 [32m✔[30m [34mpurrr [30m 0.2.5
[32m✔[30m [34mtibble [30m 1.4.2 [32m✔[30m [34mdplyr [30m 0.7.6
[32m✔[30m [34mtidyr [30m 0.8.1 [32m✔[30m [34mstringr[30m 1.3.1
[32m✔[30m [34mreadr [30m 1.1.1 [32m✔[30m [34mforcats[30m 0.3.0[39m
[30m── [1mConflicts[22m ────────────── tidyverse_conflicts() ──
[31m✖[30m [34mdplyr[30m::[32mfilter()[30m masks [34mstats[30m::filter()
[31m✖[30m [34mdplyr[30m::[32mlag()[30m masks [34mstats[30m::lag()[39m
Shapes
- Try a scatterplot of
gdpPercap vs pop with a categorical variable (continent) as shape.
gvsl <- ggplot(gapminder, aes(gdpPercap, lifeExp))+
scale_x_log10()
gvsl + geom_point(aes(shape=continent),alpha=0.2)

- As with all (?) aesthetics, we can also have them not as aesthetics!
- Try some shapes: first as integer from 0-24, then as keyboard characters.
- What’s up with
pch?
gvsl + geom_point(shape = 7)

gvsl + geom_point(pch = 7)

gvsl + geom_point(shape = '$')

List of shapes can be found at the bottom of the scale_shape documentation.
Colour
Make a scatterplot. Then:
- Try colour as categorical variable.
gvsl + geom_point(aes(colour = continent))

- Try
colour and color.
- Try colour as numeric variable.
- Try
trans="log10" for log scale.
gvsl + geom_point(aes(colour = pop)) + scale_colour_continuous(trans = "log10")

gvsl + geom_point(aes(colour = lifeExp > 60))

Make a line plot of gdpPercap over time for all countries. Colour by lifeExp > 60 (remember that lifeExp looks bimodal?)
Try adding colour to a histogram. How is this different?
ggplot(gapminder, aes(lifeExp)) +
geom_histogram(aes(fill = continent))

Facetting
Make histograms of gdpPercap for each continent. Try the scales and ncol arguments.
ggplot(gapminder, aes(lifeExp)) +
facet_wrap( ~ continent, scales="free_x") +
geom_histogram()

Remove Oceania. Add another variable: lifeExp > 60.
ggplot(gapminder, aes(gdpPercap)) +
facet_grid(continent ~ lifeExp > 60) +
geom_histogram()

Bubble Plots
- Add a
size aesthetic to a scatterplot. What about cex?
gvsl + geom_point(aes(size=pop), alpha=0.2) +
scale_size_area()

- Try adding
scale_radius() and scale_size_area(). What’s better?
- Use
shape=21 to distinguish between fill (interior) and colour (exterior).
gvsl + geom_point(aes(size = pop, fill=continent), shape=21, colour="black", alpha=0.2)

“Complete” plot
Let’s try plotting much of the data.
- gdpPercap vs lifeExp with pop bubbles
- facet by year
- colour by continent
gvsl + geom_point(aes(size=pop, colour=continent)) +
scale_size_area() +
facet_wrap(~ year)

Continue from last time (geom exploration with x and y aesthetics)
Path plots
Let’s see how Rwanda’s life expectancy and GDP per capita have evolved over time, using a path plot.
gapminder %>%
filter(country == "Rwanda") %>%
arrange(year) %>%
ggplot(aes(gdpPercap, lifeExp)) +
# scale_x_log10() +
geom_point() +
geom_path(arrow = arrow())

- Try
geom_line(). Try geom_point().
- Add
arrow=arrow() option.
- Add
geom_text, with year label.
Two categorical variables
Try cyl (number of cylinders) ~ am (transmission) in the mtcars data frame.
- Scatterplot? Jitterplot? No.
geom_count().
geom_bin2d(). Compare with geom_tile() with fill aes.
ggplot(mtcars, aes(factor(cyl), factor(am)))+
geom_bin2d()

Overplotting
Try a scatterplot with:
- Alpha transparency.
geom_hex()
geom_density2d()
geom_smooth()
gvsl + geom_hex()

gvsl + geom_density2d()

gvsl + geom_point(alpha=0.1)+geom_smooth(method="lm")

Bar plots
How many countries are in each continent? Use the year 2007.
- After filtering the gapminder data to 2007, make a bar chart of the number of countries in each continent. Store everything except the geom in the variable
d.
gapminder %>%
filter(year == 2007) %>%
ggplot(aes(x=continent)) +
geom_bar()

- Notice the y-axis. Oddly,
ggplot2 doesn’t make it obvious how to change to proportion. Try adding a y aesthetic: y=..count../sum(..count..).
Uses of bar plots: Get a sense of relative quantities of categories, or see the probability mass function of a categorical random variable.
Polar coordinates
- Add
coord_polar() to a scatterplot.
gvsl + geom_point() + coord_polar()

Want more practice?
If you’d like some practice, give these exercises a try
Exercise 1: Make a plot of year (x) vs lifeExp (y), with points coloured by continent. Then, to that same plot, fit a straight regression line to each continent, without the error bars. If you can, try piping the data frame into the ggplot function.
ggplot(gapminder, aes(year,lifeExp)) +
geom_point(aes(colour=continent)) +
geom_smooth(method="lm", aes(colour=continent))

Exercise 2: Repeat Exercise 1, but switch the regression line and geom_point layers. How is this plot different from that of Exercise 1?
ggplot(gapminder, aes(year,lifeExp)) +
geom_smooth(method="lm", aes(colour=continent)) +
geom_point(aes(colour=continent))

Exercise 3: Omit the geom_point layer from either of the above two plots (it doesn’t matter which). Does the line still show up, even though the data aren’t shown? Why or why not?
ggplot(gapminder, aes(year,lifeExp)) +
geom_smooth(method="lm", aes(colour=continent))

Exercise 4: Make a plot of year (x) vs lifeExp (y), facetted by continent. Then, fit a smoother through the data for each continent, without the error bars. Choose a span that you feel is appropriate.
ggplot(gapminder, aes(year,lifeExp)) +
facet_wrap( ~ continent) +
geom_smooth(method="lm", aes(colour=continent)) +
geom_point(aes(colour=continent))

Exercise 5: Plot the population over time (year) using lines, so that each country has its own line. Colour by gdpPercap. Add alpha transparency to your liking.
Exercise 6: Add points to the plot in Exercise 5.
LS0tCnRpdGxlOiAiY20wMDcgRXhlcmNpc2VzOiBFeHBsb3JpbmcgQWVzdGhldGljIE1hcHBpbmdzIgpvdXRwdXQ6IGdpdGh1Yl9kb2N1bWVudAplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgoKIyBCZXlvbmQgdGhlIHggYW5kIHkgYWVzdGhldGljcwoKU3dpdGNoIGZvY3VzIHRvIGV4cGxvcmluZyBhZXN0aGV0aWMgbWFwcGluZ3MsIGluc3RlYWQgb2YgZ2VvbXMuIApgYGB7cn0KbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMjIFNoYXBlcwoKLSBUcnkgYSBzY2F0dGVycGxvdCBvZiBgZ2RwUGVyY2FwYCB2cyBgcG9wYCB3aXRoIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgKGNvbnRpbmVudCkgYXMgYHNoYXBlYC4KYGBge3J9Cmd2c2wgPC0gZ2dwbG90KGdhcG1pbmRlciwgYWVzKGdkcFBlcmNhcCwgbGlmZUV4cCkpKwogIHNjYWxlX3hfbG9nMTAoKQpndnNsICsgZ2VvbV9wb2ludChhZXMoc2hhcGU9Y29udGluZW50KSxhbHBoYT0wLjIpCmBgYAoKLSBBcyB3aXRoIGFsbCAoPykgYWVzdGhldGljcywgd2UgY2FuIGFsc28gaGF2ZSB0aGVtIF9ub3RfIGFzIGFlc3RoZXRpY3MhCiAgICAtIFRyeSBzb21lIHNoYXBlczogZmlyc3QgYXMgaW50ZWdlciBmcm9tIDAtMjQsIHRoZW4gYXMga2V5Ym9hcmQgY2hhcmFjdGVycy4KICAgIC0gV2hhdCdzIHVwIHdpdGggYHBjaGA/CmBgYHtyfQpndnNsICsgZ2VvbV9wb2ludChzaGFwZSA9IDcpCmd2c2wgKyBnZW9tX3BvaW50KHBjaCA9IDcpCmd2c2wgKyBnZW9tX3BvaW50KHNoYXBlID0gJyQnKQpgYGAKCkxpc3Qgb2Ygc2hhcGVzIGNhbiBiZSBmb3VuZCBbYXQgdGhlIGJvdHRvbSBvZiB0aGUgYHNjYWxlX3NoYXBlYCBkb2N1bWVudGF0aW9uXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvc2NhbGVfc2hhcGUuaHRtbCkuCgojIyBDb2xvdXIKCk1ha2UgYSBzY2F0dGVycGxvdC4gVGhlbjoKCi0gVHJ5IGNvbG91ciBhcyBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KYGBge3J9Cmd2c2wgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb250aW5lbnQpKQpgYGAKCi0gVHJ5IGBjb2xvdXJgIGFuZCBgY29sb3JgLiAKLSBUcnkgY29sb3VyIGFzIG51bWVyaWMgdmFyaWFibGUuCiAgICAtIFRyeSBgdHJhbnM9ImxvZzEwImAgZm9yIGxvZyBzY2FsZS4KYGBge3J9Cmd2c2wgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBwb3ApKSArIHNjYWxlX2NvbG91cl9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikKZ3ZzbCArIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGxpZmVFeHAgPiA2MCkpCmBgYAoKCk1ha2UgYSBsaW5lIHBsb3Qgb2YgYGdkcFBlcmNhcGAgb3ZlciB0aW1lIGZvciBhbGwgY291bnRyaWVzLiBDb2xvdXIgYnkgYGxpZmVFeHAgPiA2MGAgKHJlbWVtYmVyIHRoYXQgYGxpZmVFeHBgIGxvb2tzIGJpbW9kYWw/KQoKClRyeSBhZGRpbmcgY29sb3VyIHRvIGEgaGlzdG9ncmFtLiBIb3cgaXMgdGhpcyBkaWZmZXJlbnQ/CmBgYHtyfQpnZ3Bsb3QoZ2FwbWluZGVyLCBhZXMobGlmZUV4cCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKGZpbGwgPSBjb250aW5lbnQpKQpgYGAKCiMjIEZhY2V0dGluZwoKTWFrZSBoaXN0b2dyYW1zIG9mIGBnZHBQZXJjYXBgIGZvciBlYWNoIGNvbnRpbmVudC4gVHJ5IHRoZSBgc2NhbGVzYCBhbmQgYG5jb2xgIGFyZ3VtZW50cy4gCmBgYHtyfQpnZ3Bsb3QoZ2FwbWluZGVyLCBhZXMobGlmZUV4cCkpICsKICBmYWNldF93cmFwKCB+IGNvbnRpbmVudCwgc2NhbGVzPSJmcmVlX3giKSArCiAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKClJlbW92ZSBPY2VhbmlhLiBBZGQgYW5vdGhlciB2YXJpYWJsZTogYGxpZmVFeHAgPiA2MGAuIApgYGB7cn0KZ2dwbG90KGdhcG1pbmRlciwgYWVzKGdkcFBlcmNhcCkpICsKICBmYWNldF9ncmlkKGNvbnRpbmVudCB+IGxpZmVFeHAgPiA2MCkgKwogIGdlb21faGlzdG9ncmFtKCkKYGBgCgojIyBCdWJibGUgUGxvdHMKCi0gQWRkIGEgYHNpemVgIGFlc3RoZXRpYyB0byBhIHNjYXR0ZXJwbG90LiBXaGF0IGFib3V0IGBjZXhgPwpgYGB7cn0KZ3ZzbCArIGdlb21fcG9pbnQoYWVzKHNpemU9cG9wKSwgYWxwaGE9MC4yKSArCiAgc2NhbGVfc2l6ZV9hcmVhKCkKYGBgCgotIFRyeSBhZGRpbmcgYHNjYWxlX3JhZGl1cygpYCBhbmQgYHNjYWxlX3NpemVfYXJlYSgpYC4gV2hhdCdzIGJldHRlcj8KLSBVc2UgYHNoYXBlPTIxYCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGBmaWxsYCAoaW50ZXJpb3IpIGFuZCBgY29sb3VyYCAoZXh0ZXJpb3IpLgpgYGB7cn0KZ3ZzbCArIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwb3AsIGZpbGw9Y29udGluZW50KSwgc2hhcGU9MjEsIGNvbG91cj0iYmxhY2siLCBhbHBoYT0wLjIpCmBgYAoKIyMgIkNvbXBsZXRlIiBwbG90CgpMZXQncyB0cnkgcGxvdHRpbmcgbXVjaCBvZiB0aGUgZGF0YS4KCi0gZ2RwUGVyY2FwIHZzIGxpZmVFeHAgd2l0aCBwb3AgYnViYmxlcwotIGZhY2V0IGJ5IHllYXIKLSBjb2xvdXIgYnkgY29udGluZW50CmBgYHtyfQpndnNsICsgZ2VvbV9wb2ludChhZXMoc2l6ZT1wb3AsIGNvbG91cj1jb250aW5lbnQpKSArIAogIHNjYWxlX3NpemVfYXJlYSgpICsKICBmYWNldF93cmFwKH4geWVhcikKYGBgCgoKCiMgQ29udGludWUgZnJvbSBsYXN0IHRpbWUgKGdlb20gZXhwbG9yYXRpb24gd2l0aCBgeGAgYW5kIGB5YCBhZXN0aGV0aWNzKQoKIyMgUGF0aCBwbG90cwoKTGV0J3Mgc2VlIGhvdyBSd2FuZGEncyBsaWZlIGV4cGVjdGFuY3kgYW5kIEdEUCBwZXIgY2FwaXRhIGhhdmUgZXZvbHZlZCBvdmVyIHRpbWUsIHVzaW5nIGEgcGF0aCBwbG90LgpgYGB7cn0KZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoY291bnRyeSA9PSAiUndhbmRhIikgJT4lIAogIGFycmFuZ2UoeWVhcikgJT4lIAogIGdncGxvdChhZXMoZ2RwUGVyY2FwLCBsaWZlRXhwKSkgKwogICMgc2NhbGVfeF9sb2cxMCgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fcGF0aChhcnJvdyA9IGFycm93KCkpCmBgYAoKLSBUcnkgYGdlb21fbGluZSgpYC4gVHJ5IGBnZW9tX3BvaW50KClgLgotIEFkZCBgYXJyb3c9YXJyb3coKWAgb3B0aW9uLgotIEFkZCBgZ2VvbV90ZXh0YCwgd2l0aCB5ZWFyIGxhYmVsLiAKCgojIyBUd28gY2F0ZWdvcmljYWwgdmFyaWFibGVzCgpUcnkgYGN5bGAgKG51bWJlciBvZiBjeWxpbmRlcnMpIH4gYGFtYCAodHJhbnNtaXNzaW9uKSBpbiB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZS4KCi0gU2NhdHRlcnBsb3Q/IEppdHRlcnBsb3Q/IE5vLgotIGBnZW9tX2NvdW50KClgLgotIGBnZW9tX2JpbjJkKClgLiBDb21wYXJlIHdpdGggYGdlb21fdGlsZSgpYCB3aXRoIGBmaWxsYCBhZXMuCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMoZmFjdG9yKGN5bCksIGZhY3RvcihhbSkpKSsKICBnZW9tX2JpbjJkKCkKYGBgCgojIyBPdmVycGxvdHRpbmcKClRyeSBhIHNjYXR0ZXJwbG90IHdpdGg6CgotIEFscGhhIHRyYW5zcGFyZW5jeS4KLSBgZ2VvbV9oZXgoKWAKLSBgZ2VvbV9kZW5zaXR5MmQoKWAKLSBgZ2VvbV9zbW9vdGgoKWAKYGBge3J9Cmd2c2wgKyBnZW9tX2hleCgpCmd2c2wgKyBnZW9tX2RlbnNpdHkyZCgpCmd2c2wgKyBnZW9tX3BvaW50KGFscGhhPTAuMSkrZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCmBgYAoKCiMjIEJhciBwbG90cwoKSG93IG1hbnkgY291bnRyaWVzIGFyZSBpbiBlYWNoIGNvbnRpbmVudD8gVXNlIHRoZSB5ZWFyIDIwMDcuCgoxLiBBZnRlciBmaWx0ZXJpbmcgdGhlIGdhcG1pbmRlciBkYXRhIHRvIDIwMDcsIG1ha2UgYSBiYXIgY2hhcnQgb2YgdGhlIG51bWJlciBvZiBjb3VudHJpZXMgaW4gZWFjaCBjb250aW5lbnQuIFN0b3JlIGV2ZXJ5dGhpbmcgZXhjZXB0IHRoZSBnZW9tIGluIHRoZSB2YXJpYWJsZSBgZGAuCmBgYHtyfQpnYXBtaW5kZXIgJT4lIAogIGZpbHRlcih5ZWFyID09IDIwMDcpICU+JSAKICBnZ3Bsb3QoYWVzKHg9Y29udGluZW50KSkgKwogIGdlb21fYmFyKCkKYGBgCgoKCjIuIE5vdGljZSB0aGUgeS1heGlzLiBPZGRseSwgYGdncGxvdDJgIGRvZXNuJ3QgbWFrZSBpdCBvYnZpb3VzIGhvdyB0byBjaGFuZ2UgdG8gcHJvcG9ydGlvbi4gVHJ5IGFkZGluZyBhIGB5YCBhZXN0aGV0aWM6IGB5PS4uY291bnQuLi9zdW0oLi5jb3VudC4uKWAuCgoKCl9fVXNlcyBvZiBiYXIgcGxvdHNfXzogR2V0IGEgc2Vuc2Ugb2YgcmVsYXRpdmUgcXVhbnRpdGllcyBvZiBjYXRlZ29yaWVzLCBvciBzZWUgdGhlIHByb2JhYmlsaXR5IG1hc3MgZnVuY3Rpb24gb2YgYSBjYXRlZ29yaWNhbCByYW5kb20gdmFyaWFibGUuCgoKCiMjIFBvbGFyIGNvb3JkaW5hdGVzCgotIEFkZCBgY29vcmRfcG9sYXIoKWAgdG8gYSBzY2F0dGVycGxvdC4KYGBge3J9Cmd2c2wgKyBnZW9tX3BvaW50KCkgKyBjb29yZF9wb2xhcigpCmBgYAoKCiMgV2FudCBtb3JlIHByYWN0aWNlPwoKSWYgeW91J2QgbGlrZSBzb21lIHByYWN0aWNlLCBnaXZlIHRoZXNlIGV4ZXJjaXNlcyBhIHRyeQoKX19FeGVyY2lzZSAxX186IE1ha2UgYSBwbG90IG9mIGB5ZWFyYCAoeCkgdnMgYGxpZmVFeHBgICh5KSwgd2l0aCBwb2ludHMgY29sb3VyZWQgYnkgY29udGluZW50LiBUaGVuLCB0byB0aGF0IHNhbWUgcGxvdCwgZml0IGEgc3RyYWlnaHQgcmVncmVzc2lvbiBsaW5lIHRvIGVhY2ggY29udGluZW50LCB3aXRob3V0IHRoZSBlcnJvciBiYXJzLiBJZiB5b3UgY2FuLCB0cnkgcGlwaW5nIHRoZSBkYXRhIGZyYW1lIGludG8gdGhlIGBnZ3Bsb3RgIGZ1bmN0aW9uLgpgYGB7cn0KZ2dwbG90KGdhcG1pbmRlciwgYWVzKHllYXIsbGlmZUV4cCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9Y29udGluZW50KSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBhZXMoY29sb3VyPWNvbnRpbmVudCkpCmBgYAoKX19FeGVyY2lzZSAyX186IFJlcGVhdCBFeGVyY2lzZSAxLCBidXQgc3dpdGNoIHRoZSBfcmVncmVzc2lvbiBsaW5lXyBhbmQgX2dlb21cX3BvaW50XyBsYXllcnMuIEhvdyBpcyB0aGlzIHBsb3QgZGlmZmVyZW50IGZyb20gdGhhdCBvZiBFeGVyY2lzZSAxPwpgYGB7cn0KZ2dwbG90KGdhcG1pbmRlciwgYWVzKHllYXIsbGlmZUV4cCkpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgYWVzKGNvbG91cj1jb250aW5lbnQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyPWNvbnRpbmVudCkpCmBgYAoKX19FeGVyY2lzZSAzX186IE9taXQgdGhlIGBnZW9tX3BvaW50YCBsYXllciBmcm9tIGVpdGhlciBvZiB0aGUgYWJvdmUgdHdvIHBsb3RzIChpdCBkb2Vzbid0IG1hdHRlciB3aGljaCkuIERvZXMgdGhlIGxpbmUgc3RpbGwgc2hvdyB1cCwgZXZlbiB0aG91Z2ggdGhlIGRhdGEgYXJlbid0IHNob3duPyBXaHkgb3Igd2h5IG5vdD8KYGBge3J9CmdncGxvdChnYXBtaW5kZXIsIGFlcyh5ZWFyLGxpZmVFeHApKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGFlcyhjb2xvdXI9Y29udGluZW50KSkKYGBgCgoKX19FeGVyY2lzZSA0X186IE1ha2UgYSBwbG90IG9mIGB5ZWFyYCAoeCkgdnMgYGxpZmVFeHBgICh5KSwgZmFjZXR0ZWQgYnkgY29udGluZW50LiBUaGVuLCBmaXQgYSBzbW9vdGhlciB0aHJvdWdoIHRoZSBkYXRhIGZvciBlYWNoIGNvbnRpbmVudCwgd2l0aG91dCB0aGUgZXJyb3IgYmFycy4gQ2hvb3NlIGEgc3BhbiB0aGF0IHlvdSBmZWVsIGlzIGFwcHJvcHJpYXRlLgpgYGB7cn0KZ2dwbG90KGdhcG1pbmRlciwgYWVzKHllYXIsbGlmZUV4cCkpICsKICBmYWNldF93cmFwKCB+IGNvbnRpbmVudCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBhZXMoY29sb3VyPWNvbnRpbmVudCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9Y29udGluZW50KSkKYGBgCgpfX0V4ZXJjaXNlIDVfXzogUGxvdCB0aGUgcG9wdWxhdGlvbiBvdmVyIHRpbWUgKHllYXIpIHVzaW5nIGxpbmVzLCBzbyB0aGF0IGVhY2ggY291bnRyeSBoYXMgaXRzIG93biBsaW5lLiBDb2xvdXIgYnkgYGdkcFBlcmNhcGAuIEFkZCBhbHBoYSB0cmFuc3BhcmVuY3kgdG8geW91ciBsaWtpbmcuIApgYGB7cn0KCmBgYAoKX19FeGVyY2lzZSA2X186IEFkZCBwb2ludHMgdG8gdGhlIHBsb3QgaW4gRXhlcmNpc2UgNS4=